package com.captjack.rest.configuration.security;

import com.captjack.rest.entity.SysUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * Description description.....
 *
 * @author Jack Sparrow
 * @version 1.0.0
 * @date 2018/6/3 16:05
 * package com.captjack.rest.configuration.security
 */
@Component
public final class TokenAuthenticationManager {

    /**
     * token有效时间
     */
    private static final long TOKEN_EXPIRE_TIME = 1000 * 60 * 60 * 2;

    /**
     * 加密密钥
     */
    private static final String SECRET = "9debba8d-0ab5-45c9-9030-74bb6e735c37";

    /**
     * 解析时需要截取的长度
     */
    private static final int TOKEN_PREFIX_LENGTH = 18;

    /**
     * token名
     */
    private static final String TOKEN_HEADER_STRING = "authorization-token";

    /**
     * redis操作
     */
    private final RedisTemplate redisTemplate;

    /**
     * 登录
     *
     * @param response 返回
     * @param sysUser  用户
     */
    public void addAuthentication(HttpServletResponse response, SysUser sysUser) {
        // 获取token签名
        String token = getToken(sysUser);
        // 设置前缀二次加密
        String finalToken = getRandomTokenPrefix() + token;
        // 将token添加到请求头中，
        response.addHeader(TOKEN_HEADER_STRING, finalToken);
    }

    /**
     * 鉴权
     *
     * @param request 请求
     * @return 权限
     */
    public Authentication getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(TOKEN_HEADER_STRING);
        // token是否存在
        if (token != null && token.trim().length() > TOKEN_PREFIX_LENGTH) {
            String realityToken = token.substring(TOKEN_PREFIX_LENGTH);
            // redis中存在
            if ("1".equals(redisTemplate.opsForValue().get(realityToken).toString())) {
                // 解析token
                SysUser sysUser = getSysUser(realityToken);
                // 添加权限
                Set<GrantedAuthority> grantedAuthoritySet = new HashSet<>();
                // 添加角色
                grantedAuthoritySet.add((GrantedAuthority) () -> "ROLE_ccadmin");
                if (sysUser != null && sysUser.getName() != null && sysUser.getRoleid() != null) {
                    return new UsernamePasswordAuthenticationToken(sysUser.getName(), null, grantedAuthoritySet);
                }
            }
        }
        return null;
    }

    /**
     * 根据用户信息生成token
     *
     * @param sysUser 用户实体
     * @return token
     */
    private String getToken(SysUser sysUser) {
        // 超时时间
        long expireTime = System.currentTimeMillis() + TOKEN_EXPIRE_TIME;
        // 生成token
        String token = Jwts.builder()
                .setSubject(sysUser.getName())
                .setId(String.valueOf(sysUser.getId()))
                .setExpiration(new Date(expireTime))
                .claim("avatar", sysUser.getAvatar())
                .claim("email", sysUser.getEmail())
                .claim("roleId", sysUser.getRoleid())
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        // 将token存入redis
        redisTemplate.opsForValue().set(token, "1", expireTime, TimeUnit.MILLISECONDS);
        // 返回token
        return token;
    }

    /**
     * 反解析token
     *
     * @param token token字符串
     * @return 用户信息
     */
    private SysUser getSysUser(String token) {
        // 获取信息
        Claims claims = Jwts.parser().setSigningKey(SECRET).parseClaimsJws(token).getBody();
        // 解析用户信息
        SysUser sysUser = new SysUser();
        sysUser.setName(claims.getSubject());
        sysUser.setId(Integer.valueOf(claims.getId()));
        sysUser.setAvatar(claims.get("avatar", String.class));
        sysUser.setEmail(claims.get("email", String.class));
        sysUser.setRoleid(claims.get("roleId", String.class));
        return sysUser;
    }

    /**
     * 生成指定位数的随机前缀，解析时截取指定位数之后的token进行处理
     *
     * @return 获取随机的token前缀
     */
    private String getRandomTokenPrefix() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, TOKEN_PREFIX_LENGTH);
    }

    @Autowired
    TokenAuthenticationManager(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

}
